博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
项目:rbac 基于角色的权限管理系统;
阅读量:5122 次
发布时间:2019-06-13

本文共 9534 字,大约阅读时间需要 31 分钟。

- 简单示意流程图

 

- RBAC分析:

  - 基于角色的权限管理;

  - 权限等于用户可以访问的URL;

  - 通过限制URL来限制权限;

 

- RBAC表结构组成:

from django.db import modelsclass Menu(models.Model):    """    菜单表:    """    title = models.CharField(verbose_name='菜单名称', max_length=32, db_index=True)  # 创建索引    icon = models.CharField(verbose_name='图标', max_length=32)    def __str__(self):        return self.title    class Meta:        # db_table = 'menu'        verbose_name = '菜单'        verbose_name_plural = '菜单'class Jurisdiction(models.Model):    """    权限表    """    url = models.CharField(max_length=32)    title = models.CharField(verbose_name='权限名称', max_length=32)    name = models.CharField(verbose_name='反向解析别名', max_length=32, unique=True)    menu = models.ForeignKey(to='Menu', null=True, blank=True)    def __str__(self):        return self.title    class Meta:        verbose_name = '权限'        verbose_name_plural = '权限'class Role(models.Model):    """    角色表    """    name = models.CharField(verbose_name='角色名称', max_length=32)    permissions = models.ManyToManyField(to='Jurisdiction')    def __str__(self):        return self.name    class Meta:        verbose_name = '角色'        verbose_name_plural = '角色'class User(models.Model):    """用户表"""    name = models.CharField(verbose_name='用户名称', max_length=32)    password = models.CharField(verbose_name='密码', max_length=64)    roles = models.ManyToManyField(to="Role")    def __str__(self):        return self.name    class Meta:        verbose_name = '用户'        verbose_name_plural = '用户'
models表结构

  - 菜单表;(用于生成二级菜单)

    - 字段:

      - id:

      - title:

      - icon:

  - 用户表;

    - 字段:

      - id:

      - name:

      - pwd:

  - 角色表;

    - 字段:

      - id:

      - name:

  - 权限表;

    - 字段:

      - id:

      - url:

      - name:

      - menu:

  - 用户与角色关联表;

    - 字段:

      - id

      - uid

      - rid

  - 角色与权限关联表;

    - 字段:

      - id

      - rid

      - pid

 

- 请求访问流程:

  - 中间件:

    - 详情代码:

import refrom django.shortcuts import redirect, HttpResponsefrom django.utils.deprecation import MiddlewareMixinfrom django.conf import settingsclass RbacMiddleware(MiddlewareMixin):    """    权限校验的中间件    """    def process_request(self, request):        """        请求校验        :param request:        :return:        """        # 1. 处理白名单        for ele in settings.VALID_LIST:            if re.match(ele, request.path_info):                return None  # 通过白名单,无需再做权限校验        # 2. 权限校验;去session中获取权限然后对用户请求的url 一一进行匹配。        permission_dict = request.session.get(settings.RBAC_PERMISSION_SESSION_KEY)        if not permission_dict:            return redirect('/login/')        flag = False        for name, info in permission_dict.items():            reg = "^%s$" % info['url']            if re.match(reg, request.path_info):                flag = True                break        if not flag:            return HttpResponse('无权访问')
中间件代码

    - 进行白名单设置,若访问的是白名单中的URL不做任何限制,例如访问:login/   admin/.* 等等

    - 非白名单中的URL访问的验证;

      - 获取用户浏览器中的session信息,若不存在,则让用户进行登录;

 

  - login视图:

    - 登录验证:

      - 代码详情:

from django.shortcuts import render, redirectfrom rbac import modelsfrom crm.utils.md5 import gen_md5from rbac.service.permission import init_permissiondef login(request):    """    用户登录    :param request:    :return:    """    if request.method == "GET":        return render(request, 'login.html')    user = request.POST.get('user')    pwd = request.POST.get('pwd')    pwd_md5 = gen_md5(pwd)    # 根据用户名和密码去数据库校验,是否用户合法。    user_object = models.User.objects.filter(name=user, password=pwd_md5).first()    if not user_object:        return render(request, 'login.html', {
'msg': '用户名或密码错误'}) # 用户登录成功,获取用户权限信息并放入到session中。 # 初始化session数据 init_permission(user_object, request) return redirect('/user/')
login视图以及初始化入口

 

      - 获取form表单信息与数据库进行比较,验证不通过,则返回错误信息;

      - 验证通过,则进行数据初始化,并通过session写入用户浏览器中;

      - 返回重定向;

    - 数据初始化:

      - 根据用户姓名从数据库获取数据,组成相对应的数据结构,写入session;

      - 详情代码:

from django.conf import settingsdef init_permission(user, request):    """    权限初始化    :param user: 用户对象    :param request:  请求相关信息:request.session    :return: 无    """    # 1. 获取权限信息    # user.roles.all()    permission_queryset = user.roles.filter(permissions__id__isnull=False).values('permissions__id',                                                                                  'permissions__title',                                                                                  'permissions__url',                                                                                  'permissions__name',                                                                                  'permissions__menu_id',                                                                                  'permissions__menu__title',                                                                                  'permissions__menu__icon').distinct()    # 2. 将权限和菜单信息放入到session中。设计:权限和菜单的数据结构。    """    权限结构 = {        'user':{'url':'/user/'},        'user_add':{'url':'/user/add/'},        ...    }    菜单结构 = {        菜单id:{            title:'xxx',            icon:'xx',            children:[                {'title':'xxx','name':'xxx','url':'xxx'} # 能做菜单的权限            ]        }    }    生成的两种数据结构:        - permission_dict: 权限认证的字典        - menu_dict:生成二级菜单以及权限控制到按钮级别的字典    """    permission_dict = {}    menu_dict = {}    for row in permission_queryset:        permission_dict[row["permissions__name"]] = {
"url": row["permissions__url"]} if not row.get("permissions__menu_id"): continue if not menu_dict.get(row["permissions__menu_id"]): menu_dict[row["permissions__menu_id"]] = { "title": row["permissions__menu__title"], "icon": row["permissions__menu__icon"], "children": [] } menu_dict[row["permissions__menu_id"]]["children"].append( { "title": row["permissions__title"], "name": row["permissions__name"], "url": row["permissions__url"], } ) # 3. 写入session request.session[settings.RBAC_PERMISSION_SESSION_KEY] = permission_dict request.session[settings.RBAC_MENU_SESSION_KEY] = menu_dict
初始化数据结构代码

 

- 难点:

  - 表关联关系;

- 第一版:    - 根据用户所拥有的权限多少进行限制:        - 需要将用户和权限进行关联:            - 用户表            - 权限表        - 假若用户很多,以及权限很多;        - 生成的关联表中的数据十分多,不利于查询;- 第二版:    - 在第一版的基础上为用户创建角色:        - 让用户表与角色进行关联;        - 角色表与权限表进行关联;    - 通过对不同的角色赋予不同的权限,在通过用户的角色来限制用户的权限;        - 用户与角色需要多对多的关系,生成第三张关联表;            - 介与用户或许会有许多不同的角色身份            - 每个角色都会有许多用户的存在            - 生成第三张 用户与角色关联表;        - 同时 权限与角色也是需要多对多的关系:            - 每个权限都有可能会有不同的角色都使用            - 每个角色都有会有不同的多个权限使用;            - 生成第四张 角色与权限关联表- 补充:菜单表:    - 为了在生成二级菜单时,辅助生成的一张表;    - 详情可见下面的菜单结构的分析

 

  - 数据结构搭建;

    - 两种数据结构:

权限结构 = {    'user':{
'url':'/user/'}, 'user_add':{
'url':'/user/add/'}, ...}菜单结构 = { 菜单id:{ title:'xxx', icon:'xx', children:[ {
'title':'xxx','name':'xxx','url':'xxx'} # 能做菜单的权限 ] }}

  

    - 权限结构:

      - 在权限结构中,用url的别名作为key,url的路由信息作为value,组成字典;

      - 在中间件中,读取用户携带的该权限字典中所有的values,然后循环判断即可;

      - 若想省事,可以直接组成列表;

    - 菜单结构:

      - 在所有的权限中,可以做菜单的权限不多;例如:添加,删除,更改,便不能作为菜单显示,只能作为按钮显示;

      - 需要在数据库中将可以做菜单,和不可以做菜单的表做出区别;

        - 在这里采取的做法是另外创建一张菜单表,和权限表关联,如果某条权限可以作为菜单,则将该信息和菜单表进行关联,若不可,则为None;

        - 在显示菜单的时候,根据该字段是否有值来进行判断,以便于生成菜单结构字典;

      - 若该菜单id的值存在,且在菜单结构中买有该菜单id的key则新建一个字典,该字典中所对应的 children为空列表。

      - 往所有菜单id相对应的值中的字典中的children对应的列表里添加所有的信息字典;

      - 没有菜单id的权限则continue掉;

 

- 扩展点:

  - 权限控制到按钮级别;

    - 母板:

    
Title
{% load rbac %} {% menu request %}
{% block content %} {% endblock %}
简单母板

 

    - filter函数;

from django.template import Libraryfrom django.conf import settingsregister = Library()@register.filterdef has_permission(name, request):    permission_dict = request.session[settings.RBAC_PERMISSION_SESSION_KEY]    if name in permission_dict:        return True
自定义的filter

 

    - inclusion_tag函数;

# rbac.pyfrom django.template import Libraryfrom django.conf import settingsregister = Library()@register.inclusion_tag('menu.html')def menu(request):    menu_dict = request.session[settings.RBAC_MENU_SESSION_KEY]    return {
'menu_dict': menu_dict}############################ menu.html
    {
    % for menu in menu_dict.values %}
  • {
    { menu.title }}
  • {
    % endfor %}
自定义的inclusion

 

    - 继承母板以及控制到按钮级别权限的简单示例:

{% extends 'layout.html' %}{% load rbac %}{% block content %}    

右侧内容

{% if 'user_add'|has_permission:request %} 添加 {% endif %}
{% for row in data_list %}
{% endfor %}
{
{ row.name }}
{
{ row.age }}
{% if 'user_edit'|has_permission:request %} 编辑 {% endif %} {% if 'user_del'|has_permission:request %} 删除 {% endif %}
{% endblock %}
user_list.html

 

  - js控制菜单hide

  - 分页组件;

  - 

转载于:https://www.cnblogs.com/Fushengliangnian/p/9931200.html

你可能感兴趣的文章
[转]: 视图和表的区别和联系
查看>>
Regular Experssion
查看>>
图论例题1——NOIP2015信息传递
查看>>
CocoaPods的安装和使用那些事(Xcode 7.2,iOS 9.2,Swift)
查看>>
Android 官方新手指导教程
查看>>
幸运转盘v1.0 【附视频】我的Android原创处女作,请支持!
查看>>
UseIIS
查看>>
集合体系
查看>>
vi命令提示:Terminal too wide
查看>>
引用 移植Linux到s3c2410上
查看>>
MySQL5.7开多实例指导
查看>>
[51nod] 1199 Money out of Thin Air #线段树+DFS序
查看>>
Red and Black(poj-1979)
查看>>
分布式锁的思路以及实现分析
查看>>
腾讯元对象存储之文件删除
查看>>
jdk环境变量配置
查看>>
安装 Express
查看>>
包含列的索引:SQL Server索引的阶梯级别5
查看>>
myeclipse插件安装
查看>>
浙江省第十二届省赛 Beauty of Array(思维题)
查看>>